﻿import { useEffect, useState } from "react";
import "./TestPage.css";
import type { EncryptionRecord } from "../utils/encryptionMeta";
import { readEncryptionMeta, saveEncryptionMeta } from "../utils/encryptionMeta";

type DeviceInfo = {
  index: number;
  label: string;
  sn: string;
};
const ensureZjcaReady = () => {
  if ((window as any).g_ZjcaCMT) return true;
  const ctor = (window as any).zjca_CMT;
  if (!ctor) return false;

  const initWithProtocol = (proto: "https" | "http") => {
    try {
      const instance = new ctor(() => {}, null);
      instance.setProtocol(proto);
      const resp = instance.init(1, 1);
      if (resp?.code === 0) {
        (window as any).g_ZjcaCMT = instance;
        return true;
      }
    } catch (error) {
      console.warn(`使用 ${proto.toUpperCase()} 初始化失败:`, error);
    }
    return false;
  };

  if (initWithProtocol("https")) return true;
  return initWithProtocol("http");
};

const useZjcaReady = () => {
  const [ready, setReady] = useState(false);
  useEffect(() => {
    setReady(ensureZjcaReady());
  }, []);
  return ready;
};

const findEncryptCert = (zjca: any, deviceIndex: number) => {
  if (!zjca || deviceIndex < 0) return null;
  try {
    const resp = zjca.getCertList(0, 0, 2);
    if (resp?.code === 0 && Array.isArray(resp.res)) {
      const found = resp.res.find((cert: any) => {
        const keyIdx = cert.getKeyIndex ? cert.getKeyIndex() : cert.keyIndex ?? cert.getIndex?.() ?? -1;
        return keyIdx === deviceIndex || deviceIndex === -1;
      }) || resp.res[0];
      if (found) {
        const alg =
          typeof found.getAlg === "function"
            ? found.getAlg()
            : found.algorithm ?? found.alg ?? 0;
        const keyIndex =
          found.getKeyIndex ? found.getKeyIndex() : found.keyIndex ?? found.getIndex?.() ?? deviceIndex;
        return {
          deviceIndex,
          keyIndex,
          algId: alg === 2 ? 2 : 1,
          algorithmName: alg === 2 ? "SM2(国密)" : "RSA",
          subject: found.getSubjectCN ? found.getSubjectCN() : found.subjectCN ?? "未知"
        };
      }
    }
  } catch (error) {
    console.warn("枚举加密证书失败:", error);
  }
  return null;
};

const panelStyle: React.CSSProperties = {
  padding: 24,
  borderRadius: 16,
  background: "#fff",
  boxShadow: "0 10px 30px rgba(0,0,0,0.12)",
  border: "1px solid rgba(0,0,0,0.05)"
};

const buttonStyle = (bg: string, disabled = false): React.CSSProperties => ({
  minWidth: 130,
  padding: "10px 24px",
  borderRadius: 24,
  border: "none",
  fontWeight: 600,
  color: "#fff",
  cursor: disabled ? "not-allowed" : "pointer",
  background: disabled ? "#bdbdbd" : bg,
  boxShadow: disabled ? "none" : `0 4px 16px ${bg}40`,
  transition: "transform 0.2s ease"
});

const EncryptionPage = () => {
  const ready = useZjcaReady();
  const zjca = () => (window as any).g_ZjcaCMT;

  const [devices, setDevices] = useState<DeviceInfo[]>([]);
  const [deviceIndex, setDeviceIndex] = useState<number>(-1);
  const [selectedFilePath, setSelectedFilePath] = useState("");
  const [selectedFileName, setSelectedFileName] = useState("");
  const [cipherPath, setCipherPath] = useState("");
  const [cipherName, setCipherName] = useState("");
  const [lastMessage, setLastMessage] = useState("");
  const [encrypting, setEncrypting] = useState(false);
  const [decrypting, setDecrypting] = useState(false);
  const [currentCertInfo, setCurrentCertInfo] = useState<{
    subject: string;
    algorithmName: string;
  } | null>(null);
  const [cipherMeta, setCipherMeta] = useState<EncryptionRecord | null>(null);
  const [detailLines, setDetailLines] = useState<string[]>([]);
  const [detailMessage, setDetailMessage] = useState("");
  const [detailLoading, setDetailLoading] = useState(false);

  const loadDevices = () => {
    const api = zjca();
    if (!api) return;
    try {
      const resp = api.getKeyList(false);
      if (resp?.code === 0 && Array.isArray(resp.res) && resp.res.length > 0) {
        const mapped = resp.res.map((key: any) => ({
          index: key.getIndex ? key.getIndex() : key.index ?? 0,
          label: key.getLabel ? key.getLabel() : key.label ?? "未知介质",
          sn: key.getSN ? key.getSN() : key.sn ?? ""
        }));
        setDevices(mapped);
        setDeviceIndex((prev) =>
          prev >= 0 && mapped.some((item: { index: number; }) => item.index === prev)
            ? prev
            : mapped[0].index
        );
      } else {
        setDevices([]);
        setDeviceIndex(-1);
        if (resp && resp.code !== 0) {
          console.warn("获取介质列表失败:", resp.msg || resp.code);
        }
      }
    } catch (error) {
      console.warn("枚举介质失败:", (error as any)?.message || error);
      setDevices([]);
      setDeviceIndex(-1);
    }
  };

  useEffect(() => {
    if (ready) {
      loadDevices();
    }
  }, [ready]);

  useEffect(() => {
    if (!ready || deviceIndex < 0) {
      setCurrentCertInfo(null);
      return;
    }
    const api = zjca();
    if (!api) return;
    const cert = findEncryptCert(api, deviceIndex);
    if (cert) {
      setCurrentCertInfo({ subject: cert.subject, algorithmName: cert.algorithmName });
    } else {
      setCurrentCertInfo(null);
    }
  }, [ready, deviceIndex]);

  useEffect(() => {
    if (!cipherPath) {
      setCipherMeta(null);
      setDetailLines([]);
      setDetailMessage("");
      return;
    }
    const api = zjca();
    setCipherMeta(readEncryptionMeta(api, cipherPath));
    setDetailLines([]);
    setDetailMessage("");
  }, [cipherPath, ready]);

  const browseFile = () => {
    const resp = zjca()?.getFileName(true, "选择要加密的标书文件", "*.*");
    if (resp?.code === 0 && resp.res) {
      const filePath = resp.res as string;
      setSelectedFilePath(filePath);
      setSelectedFileName(filePath.split(/[/\\]/).pop() || filePath);
      setLastMessage("");
    }
  };

  const browseCipherFile = () => {
    const resp = zjca()?.getFileName(true, "选择要解密的密文文件", "*.enc;*.p7m;*.p7s;*.*");
    if (resp?.code === 0 && resp.res) {
      const filePath = resp.res as string;
      setCipherPath(filePath);
      setCipherName(filePath.split(/[/\\]/).pop() || filePath);
      setLastMessage("");
    }
  };

  const handleEncrypt = () => {
    if (!ready) return alert("ZJCA 客户端未就绪，请先在首页初始化。");
    if (deviceIndex < 0) return alert("请先选择要使用的介质。");
    if (!selectedFilePath) return alert("请先选择要加密的文件。");

    const cert = findEncryptCert(zjca(), deviceIndex);
    if (!cert) {
      alert("未检测到加密证书，请确认介质已插入并在首页成功识别。");
      return;
    }

    try {
      const pinResp = zjca()?.verifyPin(cert.keyIndex, "");
      if (pinResp?.code !== 0) {
        alert(`PIN 验证失败：${pinResp?.msg || "未知错误"}`);
        return;
      }
    } catch (error: any) {
      alert(`PIN 验证异常：${error?.message || error}`);
      return;
    }

    const saveResp = zjca()?.getFileName(
      false,
      `保存加密文件（建议：${selectedFileName}.enc）`,
      "*.enc"
    );
    if (saveResp?.code !== 0 || !saveResp.res) return;
    let destPath = saveResp.res as string;
    if (!destPath.toLowerCase().endsWith(".enc")) {
      destPath = destPath + ".enc";
    }
    if (destPath === selectedFilePath) {
      alert("输出路径不能与输入路径相同。");
      return;
    }

    const certResp = zjca()?.getCertContent(cert.keyIndex, cert.algId, 2);
    if (certResp?.code !== 0 || !certResp.res) {
      alert(`获取证书内容失败：${certResp?.msg || "未知错误"}`);
      return;
    }

    const symmAlg = cert.algId === 2 ? 0x20 : 0x04;
    const cipherType = 1;
    const paddingType = 1;

    const callback = (resp: any) => {
      setEncrypting(false);
      if (!resp || (resp.respType && resp.respType !== "encrypt_file_resp")) return;
      const code = typeof resp.code === "number" ? resp.code : resp.res ?? 0;
      if (code === 0) {
        setLastMessage(`文件加密成功！\n${destPath}`);
        alert(`文件加密成功！\n${destPath}`);
      } else {
        const msg = resp.msg || `错误码 ${code}`;
        setLastMessage(`加密失败：${msg}`);
        alert(`加密失败：${msg}`);
      }
      if (code === 0) {
        const deviceSnapshot = currentDevice;
        const certSnapshot = currentCertInfo;
        const meta: EncryptionRecord = {
          cipherPath: destPath,
          cipherName: destPath.split(/[/\\]/).pop() || destPath,
          sourcePath: selectedFilePath,
          createdAt: new Date().toISOString(),
          deviceIndex,
          deviceLabel: deviceSnapshot?.label || "未知介质",
          deviceSN: deviceSnapshot?.sn || "",
          certSubject: certSnapshot?.subject || cert.subject || "未知",
          certAlgorithm: certSnapshot?.algorithmName || cert.algorithmName
        };
        const saveResult = saveEncryptionMeta(zjca(), destPath, meta);
        if (!saveResult.ok && saveResult.message) {
          console.warn(
            `保存密文元数据失败: ${saveResult.message} (${saveResult.path || "unknown"})`
          );
        }
        setCipherMeta(meta);
        setCipherPath(destPath);
        setCipherName(meta.cipherName);
        setDetailLines([]);
        setDetailMessage("");
      }
    };

    try {
      setEncrypting(true);
      const attempts = [
        { keyIndex: -1, certBase64: certResp.res, desc: "软件加密" },
        { keyIndex: cert.keyIndex, certBase64: "", desc: "硬件加密" }
      ];
      const api = zjca();
      let immediate: any = null;
      for (const attempt of attempts) {
        immediate = api?.encryptFile(
          attempt.keyIndex,
          attempt.certBase64,
          selectedFilePath,
          destPath,
          symmAlg,
          cipherType,
          paddingType,
          callback
        );
        if (!immediate || immediate.code === 0) break;
        console.warn(`${attempt.desc} 返回错误，尝试下一种：`, immediate);
      }
      if (immediate && typeof immediate.code === "number" && immediate.code !== 0) {
        callback(immediate);
      }
    } catch (error: any) {
      setEncrypting(false);
      alert(`加密异常：${error?.message || error}`);
    }
  };

  const handleDecrypt = () => {
    const target = cipherPath || selectedFilePath;
    if (!target) return alert("请选择要解密的密文文件。");
    const lowerTarget = target.toLowerCase();
    const isCipherExt = lowerTarget.endsWith(".enc") || lowerTarget.endsWith(".p7m") || lowerTarget.endsWith(".p7s");
    if (!isCipherExt) {
      const shouldContinue = confirm(
        "⚠️ 当前选择的文件扩展名不是常见的密文格式（.enc/.p7m/.p7s）。\n\n" +
          "请确认这是经证书加密后的文件，否则解密后可能仍为空。\n\n" +
          "是否继续尝试解密？"
      );
      if (!shouldContinue) return;
    }
    if (!ready) return alert("ZJCA 客户端未就绪，请先在首页初始化。");
    if (deviceIndex < 0) return alert("请先选择要使用的介质。");

    const cert = findEncryptCert(zjca(), deviceIndex);
    if (!cert) return alert("未检测到加密证书，请确认介质包含对应私钥。");

    try {
      const pinResp = zjca()?.verifyPin(cert.keyIndex, "");
      if (pinResp?.code !== 0) {
        alert(`PIN 验证失败：${pinResp?.msg || "未知错误"}`);
        return;
      }
    } catch (error: any) {
      alert(`PIN 验证失败：${error?.message || error}`);
      return;
    }

    const suggestedName =
      (cipherName || "解密文件").replace(/\.enc$/i, "") +
      (cipherName && cipherName.includes(".") ? "" : "_解密");
    const saveResp = zjca()?.getFileName(false, `保存解密文件（建议：${suggestedName}）`, "*.*");
    if (saveResp?.code !== 0 || !saveResp.res) return;
    const destPath = (saveResp.res as string).trim();
    if (!destPath) return;
    if (destPath === target) {
      alert("输出路径不能与输入路径相同。");
      return;
    }

    const api = zjca();
    if (!api || typeof api.decryptFileUseKey !== "function") {
      alert("当前 SDK 未提供 decryptFileUseKey 接口，请检查 zjca_cmt 引入是否完整。");
      return;
    }

    const symm = cert.algId === 2 ? 0x20 : 0x04;
    const paddingType = 1;

    const callback = (resp: any) => {
      setDecrypting(false);
      if (!resp || (resp.respType && resp.respType !== "decode_file_resp")) return;
      const code = typeof resp.code === "number" ? resp.code : resp.res ?? 0;
      if (code === 0) {
        setLastMessage(`文件解密成功：\n${destPath}`);
        alert(`文件解密成功：\n${destPath}`);
      } else {
        const msg = resp.msg || `错误码 ${code}`;
        setLastMessage(`解密失败：${msg}`);
        alert(
          `解密失败：${msg}\n\n如确认使用的是加密时同一张介质，可尝试：\n1. 在首页重新初始化控件，再回到本页操作；\n2. 确保当前证书支持解密用途（usage=2）；\n3. 若为跨介质解密，请插入拥有私钥的那张介质。`
        );
      }
    };

    try {
      setDecrypting(true);
      const immediate = api.decryptFileUseKey(
        cert.keyIndex,
        cert.algId,
        symm,
        paddingType,
        target,
        destPath,
        callback
      );
      if (immediate && typeof immediate.code === "number" && immediate.code !== 0) {
        callback(immediate);
      }
    } catch (error: any) {
      setDecrypting(false);
      alert(`解密异常：${error?.message || error}`);
    }
  };

  const handleShowDeviceDetail = () => {
    if (!cipherMeta) {
      setDetailMessage("请选择包含元数据的密文文件后再查询介质详情。");
      setDetailLines([]);
      return;
    }
    const result: string[] = [
      `介质名称：${cipherMeta.deviceLabel}`,
      `介质 SN：${cipherMeta.deviceSN || "未知"}`,
      `加密证书：${cipherMeta.certSubject}（${cipherMeta.certAlgorithm}）`,
      `来源文件：${cipherMeta.sourcePath || "未记录"}`,
      `加密时间：${new Date(cipherMeta.createdAt).toLocaleString()}`
    ];
    const api = zjca();
    if (!api) {
      setDetailLines(result);
      setDetailMessage("当前未加载 ZJCA 客户端，仅展示加密时记录的信息。");
      return;
    }
    try {
      setDetailLoading(true);
      const resp = api.getKeyList?.(false);
      if (resp?.code === 0 && Array.isArray(resp.res)) {
        const match = resp.res.find((key: any) => {
          const sn = key.getSN ? key.getSN() : key.sn ?? "";
          const label = key.getLabel ? key.getLabel() : key.label ?? "";
          if (cipherMeta.deviceSN && sn) return sn === cipherMeta.deviceSN;
          return label === cipherMeta.deviceLabel;
        });
        if (match) {
          const vendor =
            (match.getManufacturer && match.getManufacturer()) ||
            match.manufacturer ||
            "";
          const desc = (match.getDesc && match.getDesc()) || match.desc || "";
          const keyType =
            match.getType ? match.getType() : match.deviceType ?? "";
          if (vendor) result.push(`生产厂商：${vendor}`);
          if (keyType) result.push(`设备类型：${keyType}`);
          if (desc) result.push(`描述：${desc}`);
        } else {
          setDetailMessage(
            "已展示加密时记录的信息，当前插入的介质中未找到匹配设备。"
          );
        }
      } else {
        setDetailMessage("已展示记录信息，但无法枚举当前介质列表。");
      }
      setDetailLines(result);
    } catch (error: any) {
      setDetailLines(result);
      setDetailMessage(
        `已展示记录信息，但从介质读取额外详情失败：${error?.message || error}`
      );
    } finally {
      setDetailLoading(false);
    }
  };

  const currentDevice = devices.find((item) => item.index === deviceIndex);

  const renderDeviceSelector = () => (
    <div
      style={{
        marginBottom: 16,
        padding: 12,
        borderRadius: 12,
        background: "#eef2ff",
        display: "flex",
        flexWrap: "wrap",
        gap: 12,
        alignItems: "center"
      }}
    >
      <span style={{ fontWeight: 600, color: "#1e3a8a" }}>使用介质：</span>
      <select
        style={{ minWidth: 220, padding: "8px 12px", borderRadius: 8 }}
        value={deviceIndex >= 0 ? deviceIndex : ""}
        onChange={(e) => setDeviceIndex(Number(e.target.value))}
      >
        {devices.length === 0 && <option value="">未检测到介质</option>}
        {devices.length > 0 && <option value="">请选择介质</option>}
        {devices.map((device) => (
          <option key={device.index} value={device.index}>
            {device.label}
            {device.sn ? ` (${device.sn})` : ""}
          </option>
        ))}
      </select>
      <button
        type="button"
        style={{ ...buttonStyle("#6366f1", false), minWidth: 100 }}
        onClick={loadDevices}
      >
        刷新介质
      </button>
    </div>
  );

  return (
    <div
      className="test-page"
      style={{
        minHeight: "100vh",
        background: "linear-gradient(135deg, #5c6bc0 0%, #3949ab 45%, #1e88e5 100%)",
        padding: 24
      }}
    >
      <div
        className="test-container"
        style={{
          maxWidth: 780,
          margin: "0 auto",
          borderRadius: 24,
          background: "rgba(255,255,255,0.95)",
          padding: 32,
          boxShadow: "0 20px 60px rgba(0,0,0,0.2)"
        }}
      >
        <div style={{ ...panelStyle }}>
          <h2 style={{ color: "#1e3a8a", marginBottom: 16 }}>标书文件加密（证书模式）</h2>
          <p style={{ color: "#4b5563", lineHeight: 1.7, marginBottom: 16 }}>
            该流程直接调用 ZJCA `encryptFile` 接口，传入介质序号、加密证书和目标路径，适合大容量标书文件，可通过 callback 异步获取结果。
          </p>
          {!ready && (
            <div
              style={{
                marginBottom: 16,
                padding: 16,
                borderRadius: 12,
                background: "#fff3e0",
                color: "#e65100"
              }}
            >
              尚未检测到 ZJCA 客户端，请先在首页初始化，再回到本页继续操作。
            </div>
          )}
        {renderDeviceSelector()}
          <div style={{ display: "flex", gap: 12, flexWrap: "wrap", marginBottom: 12 }}>
            <button onClick={browseFile} style={buttonStyle("#1976d2")}>
              选择源文件
            </button>
            <button
              onClick={handleEncrypt}
              disabled={!selectedFilePath || !ready || encrypting}
              style={buttonStyle("#ff9800", !selectedFilePath || !ready || encrypting)}
            >
              {encrypting ? "正在加密..." : "执行加密"}
            </button>
          </div>
          {selectedFilePath && (
            <p style={{ color: "#374151", marginTop: 8 }}>源文件：{selectedFileName || selectedFilePath}</p>
          )}
          <p style={{ color: "#6b7280", fontSize: 13, lineHeight: 1.6 }}>
            提示：生成的密文文件会以 <code>.enc</code> 结尾，属于二进制文件，无法直接用 Word/WPS 打开。
            请妥善保管，并配合介质解密获得原文。
          </p>
          {cipherMeta ? (
            <div
              style={{
                marginTop: 12,
                fontSize: 13,
                color: "#1f2937",
                background: "#e8f5e9",
                padding: 12,
                borderRadius: 10
              }}
            >
              <div style={{ fontWeight: 600, marginBottom: 6 }}>介质信息记录</div>
              <div>
                介质：{cipherMeta.deviceLabel}
                {cipherMeta.deviceSN ? ` (SN: ${cipherMeta.deviceSN})` : ""}
              </div>
              <div>证书：{cipherMeta.certSubject}（{cipherMeta.certAlgorithm}）</div>
              <div>来源文件：{cipherMeta.sourcePath || "未记录"}</div>
              <div>加密时间：{new Date(cipherMeta.createdAt).toLocaleString()}</div>
              <div style={{ display: "flex", gap: 12, marginTop: 10 }}>
                <button
                  type="button"
                  onClick={handleShowDeviceDetail}
                  disabled={detailLoading || !ready}
                  style={{
                    ...buttonStyle("#7c4dff", detailLoading || !ready),
                    minWidth: 140,
                    padding: "8px 18px",
                    color: "#fff"
                  }}
                >
                  {detailLoading ? "读取介质详情..." : "查看介质详情"}
                </button>
              </div>
              {(detailLines.length > 0 || detailMessage) && (
                <div
                  style={{
                    marginTop: 10,
                    padding: 12,
                    background: "#fff",
                    borderRadius: 8,
                    border: "1px solid #d1d5db",
                    color: "#1f2937"
                  }}
                >
                  {detailLines.length > 0 && (
                    <ul style={{ paddingLeft: 18, margin: 0, lineHeight: 1.6 }}>
                      {detailLines.map((line, idx) => (
                        <li key={idx}>{line}</li>
                      ))}
                    </ul>
                  )}
                  {detailMessage && (
                    <div style={{ color: "#b91c1c", fontSize: 12 }}>{detailMessage}</div>
                  )}
                </div>
              )}
            </div>
          ) : (
            <p style={{ marginTop: 12, fontSize: 13, color: "#607d8b" }}>
              如密文所在目录同时保存 <code>.zjcameta.json</code> 元数据文件，可直接展示当时使用的介质/证书信息（将该文件与密文一同流转即可）。
            </p>
          )}
        </div>

        <div style={{ ...panelStyle, marginTop: 24 }}>
          <h2 style={{ color: "#1e3a8a", marginBottom: 16 }}>标书文件解密（介质私钥）</h2>
          <p style={{ color: "#4b5563", lineHeight: 1.7, marginBottom: 16 }}>
            选择由证书加密得到的密文，插入拥有对应私钥的介质（例如原介质或备份介质 B/C），系统将调用 `decryptFileUseKey` 接口完成解密。
          </p>
        {currentDevice && (
          <div style={{ marginBottom: 12, fontWeight: 600, color: "#1e3a8a" }}>
            当前介质：{currentDevice.label}
            {currentDevice.sn ? ` (${currentDevice.sn})` : ""}
          </div>
        )}
        <div style={{ display: "flex", gap: 12, flexWrap: "wrap", marginBottom: 12 }}>
            <button onClick={browseCipherFile} style={buttonStyle("#2e7d32")}>
              选择密文文件
            </button>
            <button
              onClick={handleDecrypt}
              disabled={(!cipherPath && !selectedFilePath) || !ready || decrypting}
              style={buttonStyle("#26a69a", (!cipherPath && !selectedFilePath) || !ready || decrypting)}
            >
              {decrypting ? "正在解密..." : "执行解密"}
            </button>
          </div>
          {(cipherPath || selectedFilePath) && (
            <p style={{ color: "#374151" }}>密文：{cipherName || cipherPath || selectedFilePath}</p>
          )}
        </div>

        {lastMessage && (
          <pre
            style={{
              marginTop: 24,
              padding: 16,
              borderRadius: 12,
              background: "#f3f4f6",
              color: "#1f2937",
              whiteSpace: "pre-wrap"
            }}
          >
            {lastMessage}
          </pre>
        )}

        <div style={{ ...panelStyle, marginTop: 24, background: "#f9fafb" }}>
          <h3 style={{ color: "#1f2937", marginBottom: 12 }}>问题定位提示</h3>
          <ul style={{ color: "#4b5563", paddingLeft: 20, lineHeight: 1.6, fontSize: 13 }}>
            <li>客户端状态：{ready ? "已初始化" : "未检测到，请返回首页初始化或刷新本页"}</li>
            <li>
              当前介质：
              {currentDevice
                ? `${currentDevice.label}${currentDevice.sn ? `（SN: ${currentDevice.sn}）` : ''}`
                : "未选择/未检测到"}
            </li>
            <li>
              证书信息：
              {currentCertInfo
                ? `${currentCertInfo.subject}（${currentCertInfo.algorithmName}）`
                : "未获取到加密证书，请确认介质存在加密证书"}
            </li>
            <li>系统会在密文目录生成 <code>.zjcameta.json</code> 元数据文件，在其他电脑上也可据此查询加密介质信息。</li>
            <li>输出路径务必不同于源文件路径，必要时先复制源文件到可写目录。</li>
            <li>
              解密失败时，请确认所选介质拥有对应私钥，并确保目标文件未被占用。
            </li>
          </ul>
        </div>
      </div>
    </div>
  );
};

export default EncryptionPage;



